package com.ayou.plugin;

import com.ayou.binding.MapperProxyFactory;
import com.ayou.session.SqlSession;
import javafx.beans.binding.ObjectExpression;
import jdk.internal.org.objectweb.asm.tree.InnerClassNode;
import lombok.SneakyThrows;
import sun.plugin2.ipc.unix.UnixIPCFactory;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.*;

/**
 * @description: 插件动态代理类
 * @author: ayouman
 * @date: 2024/11/11 22:50
 */
public class Plugin implements InvocationHandler {
    private Object target;
    private Interceptor interceptor;

    private Set<Method> methods;
    public Plugin(Object target, Interceptor interceptor, Set<Method> methods) {
        this.target = target;
        this.interceptor = interceptor;
        this.methods = methods;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (methods != null && methods.contains(method)) {
            return interceptor.intercept(new Invocation(method, target, args));
        } else {
            return method.invoke(target, args);
        }
    }

    public static <T> T wrap(Object target, Interceptor interceptor) {
        Map<Class, Set<Method>> interceptorMethods = getInterceptorMethods(interceptor);
        for (Class clazz : interceptorMethods.keySet()) {
            if (clazz.isAssignableFrom(target.getClass())) {
                // 如果是要代理的类
                Set<Method> methods = interceptorMethods.get(clazz);
                return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new Plugin(target, interceptor, methods));
            } else {
                return (T) target;
            }
        }
        return (T) target;
    }

    @SneakyThrows
    private static Map<Class, Set<Method>> getInterceptorMethods(Interceptor interceptor) {
        Map<Class, Set<Method>> methods = new HashMap<>();
        Intercepts intercepts = interceptor.getClass().getAnnotation(Intercepts.class);
        Signature[] signatures = intercepts.value();
        for (Signature signature : signatures) {
            Class<?> clazz = signature.type();
            String methodName = signature.method();
            Class<?>[] args = signature.args();
            Method method = clazz.getMethod(methodName, args);
            if (methods.containsKey(clazz)) {
                methods.get(clazz).add(method);
            } else {
                Set<Method> set = new HashSet<>();
                set.add(method);
                methods.put(clazz, set);
            }
        }
        return methods;
    }


}
